<?php
if (!defined('RADISHPHP_ROOT_PATH'))
	define('RADISHPHP_ROOT_PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);

/**
 * RadishPHP framework launcher.
 *
 * @author Lei Lee
 * @version 1.0
 */
class RadishPHP {
	/**
	 * Set current version.
	 *
	 * @var string
	 */
	private $_version = '1.0';
	
	/**
	 * Time zone.
	 *
	 * @var string
	 */
	private $_time_zone = NULL;
	
	/**
	 * User control directory.
	 *
	 * @var string
	 */
	private $_controller_dir = NULL;
	
	/**
	 * Template stored directory.
	 *
	 * @var string
	 */
	private $_template_dir = NULL;
	
	/**
	 * Cache options.
	 *
	 * @var array
	 */
	private $_cache_options = NULL;
	
	/**
	 * Cache directory.
	 *
	 * @var string
	 */
	private $_cache_dir = NULL;
	
	/**
	 * Set the basic controllers.
	 *
	 * @var array
	 */
	private $_base_controllers = NULL;
	
	/**
	 * Set the routing variable name.
	 *
	 * @var string
	 */
	private $_route_var = 'r';
	
	/**
	 * Array of database connection parameters.
	 *
	 * @var array
	 */
	private $_db_params = NULL;
	
	/**
	 * DbPdo object instance.
	 *
	 * @var DbPdo
	 */
	private $_db = NULL;
	
	/**
	 * Set the global variable name the template scope.
	 * 
	 * @var string
	 */
	private $_global_tpl_vars_name = 'site';
	
	/**
	 * Set the template scope variables.
	 * 
	 * @var array
	 */
	private $_global_tpl_vars = NULL;
	
	/**
	 * Global exception handler function name.
	 *
	 * @var string
	 */
	private $_exception_handler = NULL;
	
	/**
	 * Error handling function name.
	 *
	 * @var string
	 */
	private $_error_handler = NULL;
	
	/**
	 * Set Shutdown event callback function.
	 *
	 * @var string
	 */
	private $_shutdown_handler = NULL;
	
	/**
	 * Constructor.
	 *
	 */
	function __construct() {
		
	}
	
	/**
	 * Request dispatcher.
	 *
	 */
	function dispatcher() {
		// Set the system time zone...
		if (!is_null($this->_time_zone)) 
			date_default_timezone_set($this->_time_zone);
		
		// Set exception handler...
		if (!is_null($this->_exception_handler)) 
			set_exception_handler($this->_exception_handler);
		else 
			set_exception_handler(array($this, 'defaultExceptionHandler'));
		
		// Set the error handling function...
		if (!is_null($this->_error_handler)) 
			set_error_handler($this->_error_handler);
		/*else 
			set_error_handler(array($this, 'defaultErrorHandler'), E_USER_ERROR);*/
		
		// Set Shutdown event callback function...
		if (!is_null($this->_shutdown_handler)) {
			if ((!is_array($this->_shutdown_handler) && !is_string($this->_shutdown_handler))|| (is_array($this->_shutdown_handler) && !method_exists($this->_shutdown_handler[0], $this->_shutdown_handler[1])) || (is_string($this->_shutdown_handler) && !function_exists($this->_shutdown_handler))) 
				throw new RuntimeException('Shutdown event handler method does not exist.', -1);
			register_shutdown_function($this->_shutdown_handler);
		}
		
		// Loading custom exception classes...
		include (RADISHPHP_ROOT_PATH . 'exception/IOException.class.php');
		include (RADISHPHP_ROOT_PATH . 'exception/RuntimeException.class.php');
		include (RADISHPHP_ROOT_PATH . 'exception/NetException.class.php');
		
		// Loading route resolver...
		include (RADISHPHP_ROOT_PATH . 'core/Router.class.php');
		
		// Analysis of URL address...
		$dRouterResult = Router::analyze($this);
		
		$c_filename = $this->_controller_dir
					. DIRECTORY_SEPARATOR . $dRouterResult['Module'] 
					. DIRECTORY_SEPARATOR . $dRouterResult['Controller'] . '.class.php';
		$c_filename = Router::standardize($c_filename);
		
		if (!file_exists($c_filename)) 
			throw new FileNotFoundException('File does not exist.(File: ' . $c_filename . ')', -1);
		
		// Loading user controller class files...
		$Controller = $dRouterResult['Controller'];
		$doAction   = $dRouterResult['Action'];
		
		include (RADISHPHP_ROOT_PATH . 'interface/IController.class.php');
		include (RADISHPHP_ROOT_PATH . 'interface/BaseController.class.php');
		include (RADISHPHP_ROOT_PATH . 'interface/ICacheAdapter.class.php');
		
		// Load a custom base controller...
		if (is_string($this->_base_controllers)) {
			$d_controller_result = Router::analyze($this, $this->_base_controllers);
			$base_controller_file = rtrim($this->_controller_dir, '/\\') . (!empty($d_controller_result['Module']) ? DIRECTORY_SEPARATOR . $d_controller_result['Module'] : '') . DIRECTORY_SEPARATOR . $d_controller_result['Controller'] . '.class.php';
			if (is_file($base_controller_file)) {
				include ($base_controller_file);
			}
		} elseif (is_array($this->_base_controllers)) {
			foreach ($this->_base_controllers as $vPath) {
				$d_controller_result = Router::analyze($this, $vPath);
				$base_controller_file = rtrim($this->_controller_dir, '/\\') . (!empty($d_controller_result['Module']) ? DIRECTORY_SEPARATOR . $d_controller_result['Module'] : '') . DIRECTORY_SEPARATOR . $d_controller_result['Controller'] . '.class.php';
				if (is_file($base_controller_file)) {
					include ($base_controller_file);
				}
			}
		}
		
		// Dynamic initialization controller, and call the members of a specified method...
		include ($c_filename);
		$ob = new $Controller();
		
		if (!is_a($ob, 'IController')) 
			throw new RuntimeException(get_class($ob) . ' must inherit IController Interface.', -1);
		
		if (!is_subclass_of($ob, 'BaseController')) 
			throw new RuntimeException(get_class($ob) . ' is not a subclass of BaseController objects.', -1);
			
		if (!method_exists($ob, 'setScope')) 
			throw new RuntimeException('The method `BaseController::setScope()` undefined.', -1);
		
		if (!method_exists($ob, $doAction)) 
			throw new ClassMethodNotFoundException('Class method does not exist.(' . $Controller . '::' . $doAction . ')', -1);
		
		$ob->setScope($this);
		
		// Check the switch setting magic_quotes_gpc quotes are escaped to prevent ...
		if (get_magic_quotes_gpc()) {
			$this->deslashes($_POST);
			$this->deslashes($_GET);
		}
		
		include (RADISHPHP_ROOT_PATH . 'core/WebClient.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/Template.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/DbPdo.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/SystemData.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/FileSystem.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/Thumbnail.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/DataSerializer.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/DbTree.class.php');
		include (RADISHPHP_ROOT_PATH . 'core/Cache.class.php');
		
		// Initialize the template object ...
		$ob_tpl = new Template();
		$ob_tpl->setTemplateDir($this->_template_dir);
		if (!empty($this->_global_tpl_vars)) 
			$ob_tpl->assign($this->_global_tpl_vars_name, $this->_global_tpl_vars);
		
		// Initialize the PDO database object ...
		$this->_db = new DbPdo();
		if (is_array($this->_db_params)) 
			$this->_db->addDbParams($this->_db_params);
		
		$ob->setTemplate($ob_tpl)
		   ->setDbAdapter($this->_db)
		   ->setDataAdapter(new SystemData())
		   ->setFileSystem(new FileSystem())
		   ->setThumbnail(new Thumbnail())
		   ->setDbTree(new DbTree($this))
		   ->setCache(new Cache($this))
		   ->setWebClientAdapter(new WebClient());
		
		// If there are members of the controller method "initialize", the first call this method ...
		if (method_exists($ob, 'initialize')) 
			call_user_func(array($ob, 'initialize'));
		
		// Triggering behavioral events ...
		call_user_func(array($ob, $doAction));
		
		// Call the global controller object method of destruction ...
		register_shutdown_function(array($ob, 'destroy'));
	}
	
	/**
	 * Filter out the string escape character.
	 *
	 * @param array $data
	 */
	function deslashes(&$data) {
		if (is_array($data)) {
			foreach ($data as $key => $value) {
				if (is_array($value)) {
					$this->deslashes($data[$key]);
				} elseif (is_string($value)) {
					$data[$key] = stripslashes($value);
				}
			}
		} elseif (is_string($data)) {
			$data = stripslashes($data);
		}
	}
	
	/**
	 * The default error handler.
	 *
	 * @param int $err_no
	 * @param string $err_str
	 * @param string $err_file
	 * @param int $err_line
	 * @param array $err_ctx
	 */
	function defaultErrorHandler($err_no, $err_str, $err_file, $err_line) {
		throw new ErrorException($err_str, 0, $err_no, $err_file, $err_line);
	}
	
	/**
	 * The default exception handler.
	 *
	 * @param Exception $exception
	 */
	function defaultExceptionHandler($exception) {
		$html = <<<EOT
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Exception Found!</title>
	<style type="text/css">
	/*<![CDATA[*/
	html, body { color: #333; }
	h1 { font-family: Arial, Verdana, Tahoma; font-size: 2.5em; }
	.color_1 { color: Red; }
	.color_2 { color: Blue; }
	.color_3 { color: Gray; }
	#container { margin: 12px; }
	#errors { border: 1px solid #FFF; background: #FFF; padding: 6px; }
	#copyright { margin-top: 12px; padding-top: 12px; border-top: 1px solid #A2A2A2; font-style: italic; }
	#copyright a { color: Blue; }
	/*]]>*/
	</style>
</head>
<body>
<div id="container">
	<h1>Exception Found!</h1>
	<div id="errors">
		[Code]: <span class="color_1">{$exception->getCode()}</span><br />
		[File]: {$exception->getFile()}(Line: {$exception->getLine()})<br />
		[Message]: <span class="color_2">{$exception->getMessage()}</span><br />
		[Trace]: {$exception->__toString()}
	</div>
	<div id="copyright">RadishPHP Framework v{$this->_version} version. Powered by <a href="http://www.iooogle.com/" target="_blank">iooogle.com</a></div>
</div>
</body>
</html>
EOT;
		echo $html;
		exit(0);
	}
	
	/**
	 * Set the database connection parameters.
	 *
	 * @param array $dbParams
	 * @return RadishPHP
	 */
	function setDbParams(&$dbParams) {
		$this->_db_params = &$dbParams;
		return $this;
	}
	
	/**
	 * Set the global exception handler.
	 *
	 * @param string $exception_handler
	 * @return RadishPHP
	 */
	function setExceptionHandler($exception_handler) {
		$this->_exception_handler = $exception_handler;
		return $this;
	}
	
	/**
	 * Set the error handling function.
	 *
	 * @param string $error_handler
	 * @return RadishPHP
	 */
	function setErrorHandler($error_handler) {
		$this->_error_handler = $error_handler;
		return $this;
	}
	
	/**
	 * Set Shutdown event callback function.
	 *
	 * @param string $shutdown_handler
	 * @return RadishPHP
	 */
	function setShutdownHanlder($shutdown_handler) {
		$this->_shutdown_handler = $shutdown_handler;
		return $this;
	}
	
	/**
	 * Set the template files directory.
	 *
	 * @param string $template_dir
	 * @return RadishPHP
	 */
	function setTemplateDir($template_dir) {
		$this->_template_dir = $template_dir;
		return $this;
	}
	
	/**
	 * Set the controller stored directory.
	 *
	 * @param string $controller_dir
	 * @return RadishPHP
	 */
	function setControllerDir($controller_dir) {
		$this->_controller_dir = $controller_dir;
		return $this;
	}
	
	/**
	 * Set the cache directory.
	 *
	 * @param string $cache_dir
	 * @return RadishPHP
	 */
	function setCacheDir($cache_dir) {
		$this->_cache_dir = $cache_dir;
		return $this;
	}
	
	/**
	 * Set the time zone.
	 *
	 * @param string $time_zone
	 * @return RadishPHP
	 */
	function setTimeZone($time_zone) {
		$this->_time_zone = $time_zone;
		return $this;
	}
	
	/**
	 * Set the template scope variables.
	 * 
	 * @param string $var_name
	 * @param array $var
	 * @return RadishPHP
	 */
	function setTemplateScopeVar($var_name, &$var) {
		$this->_global_tpl_vars_name = $var_name;
		$this->_global_tpl_vars = &$var;
		return $this;
	}
	
	/**
	 * Set the basic controllers.
	 *
	 * @param array $controllers
	 * @return RadishPHP
	 */
	function setBaseController($controllers) {
		$this->_base_controllers = $controllers;
		return $this;
	}
	
	/**
	 * Get the controller stored directory.
	 * 
	 * @return string
	 */
	function getControllerDir() {
		return $this->_controller_dir;
	}
	
	/**
	 * Set the routing variable name.
	 *
	 * @param string $route_var
	 * @return RadishPHP
	 */
	function setRouteVar($route_var) {
		$this->_route_var = $route_var;
		return $this;
	}
	
	/**
	 * Get the routing variable name.
	 *
	 * @return string
	 */
	function getRouteVar() {
		return $this->_route_var;
	}
	
	/**
	 * Set the cache options.
	 *
	 * @param array $options
	 * @return RadishPHP
	 */
	function setCacheOptions($options) {
		$this->_cache_options = $options;
		return $this;
	}
	
	/**
	 * Get the cache options.
	 *
	 * @return array
	 */
	function getCacheOptions() {
		return $this->_cache_options;
	}
	
	/**
	 * Get the DbPdo instance.
	 *
	 * @return DbPdo
	 */
	function getDb() {
		return $this->_db;
	}
}